#pragma once
#include "Statsheet.h"
#include "../../Global References/Globals.h"
#include "../../Item/Items.h"
#include "../../Global References/BaseObject.h"
#include "../../Global References/VectorContainer.h"
#include "../../Global References/timer.h"
#include "Local References.h"

class Engine;

//#define GODMODE
//**************************************************************************/
//This is the file for the Entity, which is used by as a Player or as an AI
//It contains an structure for the body and it's positions along with the entity class itself
// - Tyler Lawton 10/24/2011
//**************************************************************************/

struct XYZ
{
	float X, Y, Z;
	XYZ(){X = 0; Y = 0; Z = 0;}
	XYZ(float p_x, float p_y, float p_z){X = p_x; Y = p_y; Z = p_z;}
	float getX(){return X;}
	float getY(){return Y;}
	void setXY(float p_x, float p_y){X = p_x; Y = p_y;}
	void set(Vector3D var)
	{
		X = var.x;
		Y = var.y;
		Z = var.z;
	}
	void serialize(ByteBuffer* & info) {info->addFloat(X);info->addFloat(Y);info->addFloat(Z);}
	void deserialize(ByteBuffer* info, int & index)
	{ int size=sizeof(long) + sizeof(short); X = info->getFloat(index); index+=size;
	Y = info->getFloat(index); index+=size;
	Z = info->getFloat(index); index+=size;
	}
};


class Entity : public BaseObject
{
public:
	enum BodyPartIndex
	{
		e_LowerArmleft,
		e_UpperArmleft,
		e_Torso,
		e_Head,	
		e_Legsleft,
		e_Thighsleft,
		e_Legs,
		e_Thighs,
		e_LowerArm,
		e_UpperArm,
		e_TotalBPs
	};

protected:

	//////////////////
	//=====Stopwatches
	//////////////////
	stopWatch	oneTenthSecond;
	stopWatch	oneSecondTimer;
	stopWatch	twoSecondTimer;
	stopWatch	attackTimer;
	stopWatch	humanReactionTimer;


	//////////////////
	//====STATS and STATUS
	/////////////////
	char*		ms_Charactersheet;
	Statsheet	Stats;
	short		Race;
	double		sprintAcceleration;		//How much the entity may increase their horizontal momentum in a timestep
	double		sprintMaxSpeed;			//What the cap is for the entity's movement overalls
	bool		alive;
	//This variable will tell what type of entity this one is. (Player, Enemy, Gaia, null)
	//The Variables will be shared with the enum of projectile types, so P_TYPE_PLAYER, or P_TYPE_ENEMY, etc.
	int			entityType;						
	int			score;
	

	///////////////////
	//====MISC CONTAINERS(Equipment, Activities, Limbs, Effects)
	///////////////////
	Item_Equippable* wornEquipment		[MaxEquipables];	//0: Helmet 1:Cuirass 2:Gauntlets 3:Boots 4:Weaponry/Precision 5-8 Kinetic Arms
	Item_Projectile* CurrentActivity	[ACT_MAX];			//All spells, weapons, tools have a projectile. this is the one the player is using right now
	Vector<Item_Base*>		Inventory;
	Vector<effect>			EffectList;
	//====For body parts
	XYZ Placements						[e_TotalBPs];		
	XYZ Rotations						[e_TotalBPs];		
	BaseObject* BodyParts				[e_TotalBPs];
	Vector2D	SkinAssets				[e_TotalBPs];
	bool		activeSounds			[WAV_MAXSOUNDS];
	//====Momentums
	Vector2D Momentums[MOM_NUM];
	Vector2D FinalMomentum;
	void CalcMomentum();
	

	////////////////////////////////////////
	//=========Damage and attacking related
	////////////////////////////////////////
	short PierceThreshold, resistPierce, currentPierce;		//When they die, what they negate, current damage
	short ImpactThreshold, resistImpact, currentImpact;		//When they die, what they negate, current damage
	short EnergyThreshold, resistEnergy, currentEnergy;		//When they die, what they negate, current damage
	short attackSpeed;


	///////////////////////
	//====AI and perks
	///////////////////////
	int indexofTarget, distancetoTarget;
	short Mania, Aggression, Discipline;					
	Vector3D AI_TargetPos;
	double agroSphere, flockRange, wanderRange;

	void NPC_HandleAI(Vector<Entity*> * EntityList);	//May take parameters laters
	void NPC_RecalcAI();	//Used to calculate the AI parameters to follow
	void NPC_RefreshTarget(Vector<Entity*> * EntityList);
	int	 NPC_PollDistance(Entity * Target);
	void NPC_HandleManic(Vector<Entity*> * a_EntityList);	//Manic
	void NPC_HandleAngry(Vector<Entity*> * a_EntityList);	//Aggro
	void NPC_HandleStoic(Vector<Entity*> * a_EntityList);	//Dicipline
	void AI_TrackTarget(Vector3D target);


	/////////////////////////
	//====Magic
	/////////////////////////
	float Meta;				//Total Magic
	short spellCharge;		//How long the player has been charging the spell
	
	void createSpell();
	void chargeSpell();		//Charge up the current spell so long as RMB is held
	void castSpell();		//Cast the spell when RMB is released


	//////////////////////
	//=====Private Initializers
	/////////////////////
	void CreateLimbs(int type);
	void DetermineRace();


	//////////////////////////
	//=====Private Updates
	//////////////////////////
	void UpdateLimbs();
	void Flip(int lastXDir);
	void SwingWeapons();
	void Death();


	//////////////////////////
	//=====Input and Action handlers
	//////////////////////////
	void HandleMovement();
	void HandleActions();


	//////////////////////////
	//=====Collision: Rockwell
	//////////////////////////
	short myJumpState;
	bool CollidedDirections[DIR_SIZE];


	//////////////////////////
	//=====Interactions with Equipment
	//////////////////////////
	void EquipItem(int Slot, int index);
	void UnequipItem(int Slot);
	void UpdateWornItems();
	void UpdateEffects();
	void UpdateStatistics();




public:
	////////////////////////
	//=====(De)Constructors
	////////////////////////
	Entity();
	void destroyCharacter();
	~Entity();


	//////////////////////////
	//=====Collision: Rockwell
	//////////////////////////
	bool CheckCollision(void * Data, bool lastXDirs[]);


	//////////////////////////
	//=====CASTING
	//////////////////////////
	bool projectileHasHit(Item_Projectile* item, int Tex, Vector2D iconAsset, char* Name);


	//////////////////////////
	//====Public Variables
	//////////////////////////
	int playerIndex;			//The Index of the Player in the queue of entities
	Vector<int> MovementQueue; //This will be used to hold messages of entities moving
	Vector<int> ActivityQueue; //This will be used to hold messages of the entities actions such as swinging and equipping
	stopWatch	timer;
	bool		activeAnimations		[ANI_MAX];
	int			currentFrames			[ANI_MAX];
	short		lastXDir;




	//////////////////////////
	//=====Initializers
	//////////////////////////
	void loadCharacter(char* s_Charactersheet, int type);
	void saveCharacter(char* s_Charactersheet);


	//////////////////////////
	//=====Mutators
	//////////////////////////
	void setEntityType(int type) { entityType = type; }
	void setDamages(short p, short i, short e);
	bool AddItemtoInv(Item_Base* p_Basey);
	bool removeBlockFromInv(char* blockName);
	bool UpdateEntity(Vector<Entity*> * EntityList);


	//////////////////////////
	//=====Player Character Functions
	//////////////////////////
	void PC_handleGuiMessage(Vector3D Message);
	void PC_handleScore(int scoretoAdd);
	void PC_UseConsumable(int index);


	//////////////////////////
	//=====Accessors
	//////////////////////////
	void CalcBBDimensions(float& width, float& height); //~When you want dimensions for a bounding box, you want this.
	Item_Projectile * GetCurrentAction(int p_index);
	int getEntType() { return entityType; }
	short getPierceDmg() { return currentPierce; }
	short getImpactDmg() { return currentImpact; }
	short getEnergyDmg() { return currentEnergy; }
	BaseObject* getBodyPart(int index) { return BodyParts[index]; }
	XYZ*		getPlacements(){return Placements;}
	Vector2D	getMomentum() { return FinalMomentum; }
	bool*		getActiveSounds(){return activeSounds;}
	bool		isAlive(){return alive;}
	short		getScore(){return score;}
	

	//////////////////////////
	//=====MISC (Damage Functions, Limb placements, Momentums and Sounds)
	//////////////////////////
	void WipeActionList();
	bool TakeDamage(Item_Projectile* hitSource);
	void resetPlayerfromDeath();
	void setPlacements(XYZ p_newPlacements[]);
	void setRotations(XYZ p_newRotations[]);
	void setMomentum(Vector2D p) { FinalMomentum = p; }
	void resetActiveSounds(){for(int i = 0; i < WAV_MAXSOUNDS; i++)	activeSounds[i] = false;}


	////////////////////////
	//====Multiplayer
	////////////////////////
	// serialization functions for sending entity data across a network
	void serialize(ByteBuffer* & info);
	void deserialize(ByteBuffer* info, int & index);
	void EquipItem(int Slot, Item_Equippable* item);
	void UnequipItemM(int Slot);
	void UpdateSecondaryEntity();
	void CalcMomentumM(Vector3D pos, Vector2D p);
	
	int uniqueID;
	bool bDummy;
	bool bGravity;
};